<template>
  <!--
  此组件为工具类组件，用于计算两个区间交集和并集
  -->
</template>

<script>
// 全集
const infinity = {
  left: "-infinity",
  leftContain: false,
  right: "+infinity",
  rightContain: false
}

// 空集
const empty = {
  left: "null",
  leftContain: false,
  right: "null",
  rightContain: false
}

export default {
  /**
   * 无穷
   */
  infinity,

  /**
   * 空集
   */
  empty,

  /**
   * 计算两个区间的交集和并集
   *
   * 两个集合运算的可能情况：
   * 【1】        C2
   *     C1    |----|
   *   |----|  |    |
   * ----------------------
   * 【2】
   *        |----|
   *   |----|    |
   * ----------------------
   * 【3】
   *        |-------|
   *   |----|--|    |
   * ----------------------
   * 【4】等价于【3】
   *   |------------|
   *   |------|     |
   * ----------------------
   * 【5】
   *   |------------|
   *   |  |------|  |
   * ----------------------
   * 【6】
   *      |-----|
   *   |--|     |---|
   * ----------------------
   * 【7】等价于【5】
   *   |------------|
   *   |     |------|
   * ----------------------
   * 【8】
   *   |---------|
   *   |     |---|--|
   * ----------------------
   * 【9】
   *   |-----|
   *   |     |-----|
   * ----------------------
   * 【10】
   *   |-----|
   *   |     | |----|
   * ----------------------
   * 【10】等价与【3】
   *   |----------|
   *   |----------|
   * ----------------------
   * 【11】等价与【1】
   *           |--------
   *   |----|  |
   * ----------------------
   * 【12】等价与【10】
   *           |----|
   *   -----|  |    |
   * ----------------------
   * 【13】等价与【1】
   *           |----
   *   -----|  |
   * ----------------------
   * 【14】等价与【10】
   *   -----|
   *        |  |----
   * ----------------------
   * 【15】等价与【3】
   *       |----------
   *   ----|-----|
   * ----------------------
   * 【16】等价与【8】
   *   ---------|
   *      |-----|----
   * ----------------------
   *
   * @param condition1 第一个区间
   * @param relation 区间运算 and:0, or:1
   * @param condition2 第二个区间
   * @return result 计算后的区间
   */
  calculate(condition1, relation, condition2) {
    if (relation === 0) { // and
      if (condition1.right === "null" || condition2.right === "null") { // 两个区间去交集，其中只要有一个为空，则结果为空
        return empty
      } else if (this.compare(condition1.right, condition2.left) < 0) { // 【1】
        return empty
      } else if (this.compare(condition1.right, condition2.left) === 0) { // 【2】
        if (condition1.rightContain === true
          && condition2.leftContain === true) {
          return {
            left: condition1.right,
            leftContain: true,
            right: condition1.right,
            rightContain: true
          }
        } else {
          return empty
        }
      } else if (this.compare(condition1.right, condition2.left) > 0
        && this.compare(condition1.right, condition2.right) <= 0
        && this.compare(condition1.left, condition2.left) <= 0) { // 【3】
        let obj = {
          left: condition2.left,
          leftContain: condition2.leftContain,
          right: condition1.right,
          rightContain: condition1.rightContain
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true && condition2.rightContain === true
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true && condition2.leftContain === true
        }
        return obj
      } else if (this.compare(condition1.left, condition2.left) > 0
        && this.compare(condition1.right, condition2.right) < 0) { // 【5】
        let obj = {
          left: condition1.left,
          leftContain: condition1.leftContain,
          right: condition1.right,
          rightContain: condition1.rightContain
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true && condition2.leftContain === true
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true && condition2.rightContain === true
        }
        return obj
      } else if (this.compare(condition1.left, condition2.left) < 0
        && this.compare(condition1.right, condition2.right) > 0) { // 【6】
        let obj = {
          left: condition2.left,
          leftContain: condition2.leftContain,
          right: condition2.right,
          rightContain: condition2.rightContain
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true && condition2.leftContain === true
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true && condition2.rightContain === true
        }
        return obj
      } else if (this.compare(condition2.right, condition1.left) < 0) { // 【10】
        return empty
      } else if (condition2.right === condition1.left) { // 【9】
        if (condition2.rightContain === true && condition1.leftContain === true) {
          return {
            left: condition2.right,
            leftContain: true,
            right: condition2.right,
            rightContain: true
          }
        } else {
          return empty
        }
      } else if (this.compare(condition2.right, condition1.left) > 0
        && this.compare(condition2.right, condition1.right) <= 0
        && this.compare(condition2.left, condition1.left) <= 0) { // 【8】
        let obj = {
          left: condition1.left,
          leftContain: condition1.leftContain,
          right: condition2.right,
          rightContain: condition2.rightContain
        }
        if (condition2.right === condition1.right) {
          obj.rightContain = condition2.rightContain === true && condition1.rightContain === true
        }
        if (condition2.left === condition1.left) {
          obj.leftContain = condition2.leftContain === true && condition1.leftContain === true
        }
        return obj
      }
    } else if (relation === 1) { // or
      if (condition1.right === "null" && condition2.right === "null") {
        return empty
      } else if (this.compare(condition1.right, condition2.left) < 0) { // 【1】
        return [condition1, condition2]
      } else if (this.compare(condition1.right, condition2.left) === 0) { // 【2】
        if (condition1.rightContain === false
          && condition2.leftContain === false) {
          return [condition1, condition2]
        } else {
          return {
            left: condition1.left,
            leftContain: condition1.leftContain,
            right: condition2.right,
            rightContain: condition2.rightContain
          }
        }
      } else if (this.compare(condition1.right, condition2.left) > 0
        && this.compare(condition1.right, condition2.right) <= 0
        && this.compare(condition1.left, condition2.left) <= 0) { // 【3】
        let obj = {
          left: condition1.left,
          leftContain: condition1.leftContain,
          right: condition2.right,
          rightContain: condition2.rightContain
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true || condition2.rightContain === true
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true || condition2.leftContain === true
        }
        return obj
      } else if (this.compare(condition1.left, condition2.left) > 0
        && this.compare(condition1.right, condition2.right) < 0) { // 【5】
        let obj = {
          left: condition2.left,
          leftContain: condition2.leftContain,
          right: condition2.right,
          rightContain: condition2.rightContain
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true || condition2.leftContain === true
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true || condition2.rightContain === true
        }
        return obj
      } else if (this.compare(condition1.left, condition2.left) < 0
        && this.compare(condition1.right, condition2.right) > 0) { // 【6】
        let obj = {
          left: condition1.left,
          leftContain: condition1.leftContain,
          right: condition1.right,
          rightContain: condition1.rightContain
        }
        if (condition1.left === condition2.left) {
          obj.leftContain = condition1.leftContain === true || condition2.leftContain === true
        }
        if (condition1.right === condition2.right) {
          obj.rightContain = condition1.rightContain === true || condition2.rightContain === true
        }
        return obj
      } else if (this.compare(condition2.right, condition1.left) < 0) { // 【10】
        return [condition1, condition2]
      } else if (condition2.right === condition1.left) { // 【9】
        if (condition2.rightContain === true || condition1.leftContain === true) {
          return {
            left: condition2.left,
            leftContain: condition2.leftContain,
            right: condition1.right,
            rightContain: condition1.rightContain
          }
        } else {
          return [condition1, condition2]
        }
      } else if (this.compare(condition2.right, condition1.left) > 0
        && this.compare(condition2.right, condition1.right) <= 0
        && this.compare(condition2.left, condition1.left) <= 0) { // 【8】
        let obj = {
          left: condition2.left,
          leftContain: condition2.leftContain,
          right: condition1.right,
          rightContain: condition1.rightContain
        }
        if (condition2.right === condition1.right) {
          obj.rightContain = condition2.rightContain === true || condition1.rightContain === true
        }
        if (condition2.left === condition1.left) {
          obj.leftContain = condition2.leftContain === true || condition1.leftContain === true
        }
        return obj
      }
    }
  },

  /**
   * 比较两个数的大小
   *
   * @param x 数字或者infinity（无穷大）或者null（空）
   * @param y 数字或者infinity（无穷大）或者null（空）
   * @returns {number} 如果大于0则x大于y，如果等于0则x=y，如果小于0则x小于y
   */
  compare(x, y) {
    if (typeof x === "number" && typeof y === "number") {
      if (x > y) {
        return 1
      } else if (x === y) {
        return 0
      } else {
        return -1
      }
    } else if (x === "+infinity" && typeof y === "number") {
      return 1
    } else if (x === "+infinity" && y === "-infinity") {
      return 1
    } else if (x === "+infinity" && y === "+infinity") {
      return 0
    } else if (typeof x === "number" && y === "-infinity") {
      return 1
    } else if (typeof x === "number" && y === "+infinity") {
      return -1
    } else if (x === "-infinity" && typeof y === "number") {
      return -1
    } else if (x === "-infinity" && y === "-infinity") {
      return 0
    } else if (x === "-infinity" && y === "+infinity") {
      return -1
    } else if (x === "null" && y === "null") {
      return 0
    }
  },

  name: "CalculateInterval"
}
</script>

<style scoped>

</style>
